/*
 * adpMedFilter.h
 *
 *  Created on: 2011-3-17
 *      Author: body
 */

/*
 * algorithm（实现函数adaptiveMediaFilter所采用的自适应中值滤波算法如下所描述）
 *
 * Abstract:When the digital images are made and collected, work environment and character
 * of device, give lots of disturbing to the original images. The disturbing worsens the image quality,
 * and gives lots of difficulties to analysis. So, filtering the noises is necessary. In this paper, based
 * on Cyclone II FPGA, using 3×3 image window and 5×5 image window, combine 3×3 median
 * filter and 5×5 median filter, realizing an adaptive median filter. Some false color enhancement
 * transform step is used. With the using of adaptive median filter and false color enhancement, we
 * can not only filter the noises and save the image’s detail, but also can enhance the image’s
 * information.
 * According to experiment’s results, the adaptive median filter in this paper has the advantages
 * of high speed, higher performance and high anti-interference ability.
 */


#ifndef ADPMEDFILTER_H_
#define ADPMEDFILTER_H_

#include <cv.h>
#include <highgui.h>
#include <iostream>

void adaptiveMediaFilter(IplImage* img);
int findMax(int* value, int length);
int findMin(int* value, int length);
int findMid(int* value, int length);
inline int findFurtherValue(IplImage* img, int i, int j);
inline int findProperValue(IplImage* img, int i, int j);


//采用5X5的Filter再次进行确定中值滤波后的取值

inline int findFurtherValue(IplImage* img, int i, int j){
	CvScalar s00, s01, s02, s03, s04;
	CvScalar s10, s11, s12, s13, s14;
	CvScalar s20, s21, s22, s23, s24;
	CvScalar s30, s31, s32, s33, s34;
	CvScalar s40, s41, s42, s43, s44;

	s00 = cvGet2D(img, i-2, j-2);
	s01 = cvGet2D(img, i-2, j-1);
	s02 = cvGet2D(img, i-2, j);
	s03 = cvGet2D(img, i-2, j+1);
	s04 = cvGet2D(img, i-2, j+2);

	s10 = cvGet2D(img, i-1, j-2);
	s11 = cvGet2D(img, i-1, j-1);
	s12 = cvGet2D(img, i-1, j);
	s13 = cvGet2D(img, i-1, j+1);
	s14 = cvGet2D(img, i-1, j+2);

	s20 = cvGet2D(img, i, j-2);
	s21 = cvGet2D(img, i, j-1);
	s22 = cvGet2D(img, i, j);
	s23 = cvGet2D(img, i, j+1);
	s24 = cvGet2D(img, i, j+2);

	s30 = cvGet2D(img, i+1, j-2);
	s31 = cvGet2D(img, i+1, j-1);
	s32 = cvGet2D(img, i+1, j);
	s33 = cvGet2D(img, i+1, j+1);
	s34 = cvGet2D(img, i+1, j+2);

	s40 = cvGet2D(img, i+2, j-2);
	s41 = cvGet2D(img, i+2, j-1);
	s42 = cvGet2D(img, i+2, j);
	s43 = cvGet2D(img, i+2, j+1);
	s44 = cvGet2D(img, i+2, j+2);

	int value[] = {
			s00.val[0], s01.val[0], s02.val[0], s03.val[0], s04.val[0],
			s10.val[0], s11.val[0], s12.val[0], s13.val[0], s14.val[0],
			s20.val[0], s21.val[0], s22.val[0], s23.val[0], s24.val[0],
			s30.val[0], s31.val[0], s32.val[0], s33.val[0], s34.val[0],
			s40.val[0], s41.val[0], s42.val[0], s43.val[0], s44.val[0]
	};

	int max = findMax(value, 25);
	int min = findMin(value, 25);
	int mid = findMid(value, 25);
	int mxy = s22.val[0];

	if(mid < max && mid > min){
		if(mxy < max && mxy > min){
			return mxy;
		}else{
			return mid;
		}
	}else{
			return mid;
	}

}

//采用3X3的Filter初次进行确定中值滤波后的取值

inline int findProperValue(IplImage* img, int i, int j){
	CvScalar s0, s1, s2, s3, s4, s5, s6, s7, s8;
	s0 = cvGet2D(img, i-1, j-1);
	s1 = cvGet2D(img, i-1, j);
	s2 = cvGet2D(img, i-1, j+1);
	s3 = cvGet2D(img, i, j-1);
	s4 = cvGet2D(img, i, j);
	s5 = cvGet2D(img, i, j+1);
	s6 = cvGet2D(img, i+1, j-1);
	s7 = cvGet2D(img, i+1, j);
	s8 = cvGet2D(img, i+1, j+1);

	int value[] = {
			s0.val[0], s1.val[0], s2.val[0],
			s3.val[0], s4.val[0], s5.val[0],
			s6.val[0], s7.val[0], s8.val[0]
	};

	int max = findMax(value, 9);
	int min = findMin(value, 9);
	int mid = findMid(value, 9);
	int mxy = value[4];

	if(mid < max && mid > min){
		if(mxy < max && mxy > min){
			return mxy;
		}else{
			return mid;
		}
	}else{
		if(i >= 2 && j >= 2 && j <= (img->width- 3) && i <= (img->height - 3)){
			findFurtherValue(img, i, j);
		}else{
			return mid;
		}
	}
	return mid;
}

void adaptiveMediaFilter(IplImage* img){

	cvNamedWindow("OriginalImage",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("DestinationImage",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Blue",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Green",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Red",CV_WINDOW_AUTOSIZE);

	cvMoveWindow("OriginalImage", 0, 0);
	cvMoveWindow("DestinationImage", 360, 0);
	cvMoveWindow("Blue", 0, 300);
	cvMoveWindow("Green", 360, 300);
	cvMoveWindow("Red", 720, 300);


	IplImage* src = cvCreateImage(cvGetSize(img),IPL_DEPTH_32S,CV_8SC3);
	IplImage* dst = cvCreateImage(cvGetSize(img),IPL_DEPTH_32S,CV_8SC3);
	IplImage* dstBlue = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,CV_8UC1);
	IplImage* dstRed = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,CV_8UC1);
	IplImage* dstGreen = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,CV_8UC1);

	src = cvCloneImage(img);
	dst = cvCloneImage(img);

	cvSplit(src,dstBlue,dstRed,dstGreen,NULL);

	CvScalar s;
	int i;
	for(i=1; i<dstBlue->height-1; i++){
	   for(int j=1;j<dstBlue->width-1;j++){
	        s=cvGet2D(dstBlue, i, j); // get the (i,j) pixel value
	        s.val[0] = findProperValue(dstBlue, i, j);
	        cvSet2D(dstBlue,i,j,s);//set the (i,j) pixel value
	   }
	}
	for(i=1; i<dstRed->height-1; i++){
		for(int j=1;j<dstRed->width-1;j++){
		   s=cvGet2D(dstRed, i, j); // get the (i,j) pixel value
	       s.val[0] = findProperValue(dstRed, i, j);
	       cvSet2D(dstRed,i,j,s);//set the (i,j) pixel value
	   }
	}
	for(i=1; i<dstGreen->height-1; i++){
		for(int j=1;j<dstGreen->width-1;j++){
			s=cvGet2D(dstGreen, i, j); // get the (i,j) pixel value
			s.val[0] = findProperValue(dstGreen, i, j);
			cvSet2D(dstGreen,i,j,s);//set the (i,j) pixel value
		}
	}

	cvMerge(dstBlue, dstRed, dstGreen, NULL, dst);



	cvShowImage("OriginalImage",src);
	cvShowImage("DestinationImage", dst);
	cvShowImage("Blue",dstBlue);
	cvShowImage("Green",dstGreen);
	cvShowImage("Red",dstRed);

	cvWaitKey(0);

	cvReleaseImage(&src);
	cvReleaseImage(&dst);
	cvReleaseImage(&dstRed);
	cvReleaseImage(&dstGreen);
	cvReleaseImage(&dstBlue);

}

int findMax(int* value, int length){
	int max = value[0];
	for(int i = 0; i<length; i++){
		if(value[i] >= max)
			max = value[i];
	}
	return max;
}
int findMin(int* value, int length){
	int min = value[0];
	for(int i = 0; i<length; i++){
		if(value[i] <= min)
			min = value[i];
	}
	return min;
}
int findMid(int* value, int length){
	int mid = 0;
	for(int i = 0; i<length; i++){
		mid += value[i];
	}
	mid = mid/length;
	return mid;
}

#endif /* ADPMEDFILTER_H_ */
